/*
 * Copyright (C) 31/05/2010 Aderbal Nunes <aderbalnunes@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 31/05/2010
 */

package com.boxandroid.myrom;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class GameLife extends SurfaceView implements SurfaceHolder.Callback {

	// thread game
	private GameThread _thread;
	// cache graphics
	private Map<Integer, Bitmap> _cachedImage = new HashMap<Integer, Bitmap>();
	// hide this
	private List<Graphics> _hideme = new ArrayList<Graphics>();
	// hide here
	private List<Graphics> _hideHere = new ArrayList<Graphics>();
	// context
	private Context _context;
	// random
	private Random rand;

	// for colision and selection
	int firstXRangeStart = 0;
	int firstXRangeEnd = 0;
	int firstYRangeStart = 0;
	int firstYRangeEnd = 0;

	int secondXRangeStart = 0;
	int secondXRangeEnd = 0;
	int secondYRangeStart = 0;
	int secondYRangeEnd = 0;
	int w = 120;
	int h = 120;

	private Graphics _currentSelected;
	private Graphics _currentBox;
	////////////////////////////////
	
	/**
	 * Constructor
	 * 
	 * @param context
	 */
	public GameLife(Context context) {
		super(context);
		init(context);
	}
	
	/**
	 * Constructor 
	 * 
	 * @param context
	 * @param attrs
	 */
    public GameLife(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    
    
    /**
     * Constructor 
     * 
     * @param context
     * @param attrs
     * @param defStyle
     */
    public GameLife(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	/**
     * Init Game
     * @param context
     */
    private void init(Context context){
		_context = context;
		fillCachedImages();
		_thread = new GameThread(this);
		createObjects();
		getHolder().addCallback(this);
		this.setFocusable(true);    	
    }
	
	/**
	 * Fill all bitmap on game
	 */
	private void fillCachedImages() {
		_cachedImage.put(R.drawable.android, BitmapFactory.decodeResource(
				_context.getResources(), R.drawable.android));
		_cachedImage.put(R.drawable.apple, BitmapFactory.decodeResource(
				_context.getResources(), R.drawable.apple));
		_cachedImage.put(R.drawable.close_box, BitmapFactory.decodeResource(
				_context.getResources(), R.drawable.close_box));
		_cachedImage.put(R.drawable.open_box, BitmapFactory.decodeResource(
				_context.getResources(), R.drawable.open_box));
		_cachedImage.put(R.drawable.background, BitmapFactory.decodeResource(
				_context.getResources(), R.drawable.background));
	}

	/**
	 * Create all interactive objects
	 */
	private void createObjects() {
		// create random objects
		rand = new Random();
		int xx, yy;
		for (int i = 0; i < 12; i++) {
			Graphics graphic = new Graphics();
			int r = Math.abs(rand.nextInt() % 2);
			switch (r) {
			case 0:
				graphic.set_bitmap(_cachedImage.get(R.drawable.android));
				graphic.set_type("android");
				break;
			case 1:
				graphic.set_bitmap(_cachedImage.get(R.drawable.apple));
				graphic.set_type("apple");
				break;
			default:
				throw new RuntimeException("RANDOM not between 0 and 1: "
						+ rand);
			}
			xx = rand.nextInt(400);
			yy = rand.nextInt(300);
			graphic.get_cordinates().setX(xx);
			graphic.get_cordinates().setY(yy);
			_hideme.add(graphic);
		}
		// box for android
		Graphics boxOpenAnd = new Graphics(_cachedImage
				.get(R.drawable.open_box));
		boxOpenAnd.set_type("box_android");
		boxOpenAnd.get_cordinates().setX(Util.WINDOW_W - 120);
		boxOpenAnd.get_cordinates().setY(12);
		_hideHere.add(boxOpenAnd);

		// box for apple
		 Graphics boxOpenApp = new Graphics(_cachedImage
		 .get(R.drawable.open_box));
		 boxOpenApp.set_type("box_apple");
		 boxOpenApp.get_cordinates().setX(Util.WINDOW_W - 120);
		 boxOpenApp.get_cordinates().setY(Util.WINDOW_H - 150);
		 _hideHere.add(boxOpenApp);
	}

	/**
	 * Gets objects to be touched
	 * 
	 * @param x
	 * @param y
	 * @return Graphics
	 */
	private Graphics getGraphichTouched(int x, int y) {
		for (Graphics g : _hideme) {
			firstXRangeStart = g.get_cordinates().getX();
			firstXRangeEnd = firstXRangeStart + w;
			firstYRangeStart = g.get_cordinates().getY();
			firstYRangeEnd = firstYRangeStart + h;

			secondXRangeStart = x;
			secondXRangeEnd = secondXRangeStart + w;
			secondYRangeStart = y;
			secondYRangeEnd = secondYRangeStart + h;
			if ((secondXRangeStart >= firstXRangeStart && secondXRangeStart <= firstXRangeEnd)
					|| (secondXRangeEnd >= firstXRangeStart && secondXRangeEnd <= firstXRangeEnd)) {
				if ((secondYRangeStart >= firstYRangeStart && secondYRangeStart <= firstYRangeEnd)
						|| (secondYRangeEnd >= firstYRangeStart && secondYRangeEnd <= firstYRangeEnd)) {
					return g;
				}
			}
		}
		return null;
	}

	/**
	 * Gets box replaced of object
	 * @return Graphics
	 */
	private Graphics checkBoxRigth() {
		firstXRangeStart = _currentSelected.get_cordinates().getX();
		firstXRangeEnd = firstXRangeStart + w;
		firstYRangeStart = _currentSelected.get_cordinates().getY();
		firstYRangeEnd = firstYRangeStart + h;

		for (Graphics gr : _hideHere) {
			secondXRangeStart = gr.get_cordinates().getX();
			secondXRangeEnd = secondXRangeStart + gr.get_bitmap().getWidth();
			secondYRangeStart = gr.get_cordinates().getY();
			secondYRangeEnd = secondYRangeStart + gr.get_bitmap().getHeight();
			// test
			if ((secondXRangeStart >= firstXRangeStart && secondXRangeStart <= firstXRangeEnd)
					|| (secondXRangeEnd >= firstXRangeStart && secondXRangeEnd <= firstXRangeEnd)) {
				if ((secondYRangeStart >= firstYRangeStart && secondYRangeStart <= firstYRangeEnd)
						|| (secondYRangeEnd >= firstYRangeStart && secondYRangeEnd <= firstYRangeEnd)) {
					return gr;
				}
			}
		}
		return null;
	}

	/**
	 * Touch event by user
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		/**
		 * Handler events on touch screen of game.
		 * to select objects, drag, etc
		 */
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			_currentSelected = getGraphichTouched((int) event.getX(),
					(int) event.getY());
		}
		if (event.getAction() == MotionEvent.ACTION_MOVE) {
			if (_currentSelected != null) {
				_currentSelected.moveTo((int) event.getX(), (int) event.getY());
			}
		}
		if (event.getAction() == MotionEvent.ACTION_UP) {
			if (_currentSelected != null) {
				_currentSelected.moveTo((int) event.getX(), (int) event.getY());
				_currentBox = checkBoxRigth();
				if (_currentBox != null) {
					// checks compatibility
					if (_currentBox.get_type().toLowerCase().equals(
							("box_" + _currentSelected.get_type())
									.toLowerCase())) {
						_hideme.remove(_currentSelected);
					}
				}
			}
			_currentSelected = null;
			_currentBox = null;
		}
		return true;
	}

	/**
	 * Draw objects
	 */
	@Override
	public void onDraw(Canvas canvas) {
		/**
		 * Draw all objects in game
		 */
		super.onDraw(canvas);
		canvas.drawBitmap(_cachedImage.get(R.drawable.background), 0, 0, null);
		if(_thread.get_state() == GameThread.STATE_PLAY)
			drawStatePlay(canvas);
	}
	
	/**
	 * Draw where game state = STATE_PLAY
	 * @param canvas
	 */
	private void drawStatePlay(Canvas canvas){
		if (_hideHere.size() > 0) {
			canvas.drawBitmap(_hideHere.get(0).get_bitmap(), _hideHere.get(0)
					.get_cordinates().getX(), _hideHere.get(0).get_cordinates()
					.getY(), null);
			 canvas.drawBitmap(_hideHere.get(1).get_bitmap(), _hideHere.get(1)
			 .get_cordinates().getX(), _hideHere.get(1).get_cordinates()
			 .getY(), null);
		}
		if (_hideme.size() > 0) {
			try {
				for (Graphics h : _hideme) {
					canvas.drawBitmap(h.get_bitmap(),
							h.get_cordinates().getX(), h.get_cordinates()
									.getY(), null);
				}
			} catch (Exception e) {
			}
		}		
	}

	/**
	 * Retuns Thread
	 * @return
	 */
	public GameThread getThread() {
		return _thread;
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (!_thread.isAlive()) {
			_thread = new GameThread(this);
		}
		_thread.set_run(true);
		_thread.doStart();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		boolean retry = true;
		_thread.set_run(false);
		while (retry) {
			try {
				_thread.join();
				retry = false;
			} catch (InterruptedException e) {
			}
		}
	}

	@Override
	public void onWindowFocusChanged(boolean hasWindowFocus) {
		if (!hasWindowFocus)
			_thread.pause();
	}

}
